package io.gitee.sfch.chunmi.springframework.argument;


import io.gitee.sfch.chunmi.entity.Pageable;
import io.gitee.sfch.chunmi.exception.ValidRejectException;
import jakarta.annotation.Nonnull;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * 分页参数解析器，从URL参数中解析分页参数为{@link Pageable}
 * <p>
 * 不支持从RequestBody的参数中获取{@link Pageable}，这是由于需要读取请求体才能获取到分页信息，而请求体是一个JSON
 * ，解析会消耗性能、读取流则可能会和框架冲突（has already been called for the current request）。
 * <p>
 * 为了简化及安全，这里就约定从URL参数中获取分页信息作为唯一方式
 *
 * @see Pageable
 */
@Slf4j
@Component
public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    // 分页键名
    private static final String pageNumberKey = "pageNumber";
    private static final String pageSizeKey = "pageSize";
    // 默认的分页配置
    private static final Long defaultPageNumber = 1L;
    private static final Long defaultPageSize = 10L;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(Pageable.class);
    }

    @Override
    public Object resolveArgument(@Nonnull MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();

        Long pageNumber = this.parseLongOrElse(request.getParameter(pageNumberKey), defaultPageNumber);
        Long pageSize = this.parseLongOrElse(request.getParameter(pageSizeKey), defaultPageSize);
        return Pageable.of(pageNumber, pageSize);
    }

    /**
     * 将String的参数解析为Long类型
     *
     * @param value 参数
     * @param defaultValue 默认值
     */
    private Long parseLongOrElse(String value, Long defaultValue) {
        if (!StringUtils.hasLength(value)) {
            return defaultValue;
        }
        try {
            return Long.parseLong(value);
        } catch (NumberFormatException e) {
            throw new ValidRejectException("非法分页参数:" + value);
        }
    }
}
